<template>
    <div class="app-container system-user" v-loading="isLoading">
        <sib-tree filterable default-expand-all :request-config="treeRequestConfig" @node-click="nodeClick"></sib-tree>
        <sib-table
            ref="sibTableRef"
            :search-config="searchConfig"
            :table-column="tableColumn"
            :request-config="requestConfig">
            <!-- 自定义插槽，插槽名称为对应列配置的 code -->
            <template #operate="{ row }">
                <el-button type="primary" v-hasPermi="['system:user:update']" link @click="handleEdit(row)">修改</el-button>
                <el-button type="primary" v-hasPermi="['system:user:assign-user-role']" link @click="handleAssignRole(row)">分配角色</el-button>
                <el-button type="primary" v-hasPermi="['system:user:update-password']" link @click="handleReset(row)">重置密码</el-button>
                <el-button type="danger" v-hasPermi="['system:user:delete']" link @click="handleDelete(row)">删除</el-button>
            </template>
            <!-- 自定义表单与列表之间的内容 -->
            <template #operation-container>
                <el-button type="primary" plain icon="Plus" v-hasPermi="['system:user:create']" @click="handleAdd">新增</el-button>
                <sib-item :props="importProps" v-hasPermi="['system:user:import']"></sib-item>
                <el-button type="plain" plain icon="Download" @click="handleDownload" v-hasPermi="['system:user:import']">下载模板</el-button>
                <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
            </template>
        </sib-table>
        <el-dialog
            v-if="dialogVisible"
            append-to-body
            draggable
            align-center
            v-model="dialogVisible"
            :close-on-click-modal="false"
            :title="dialogConfig.title"
            :width="dialogConfig.width || '600px'">
            <sib-form v-bind="dialogConfig" @reset="dialogVisible = false" @submit="handleSubmit"></sib-form>
        </el-dialog>
        <el-dialog
            title="分配角色"
            v-if="assignRoleDialog.visible"
            append-to-body
            draggable
            align-center
            v-model="assignRoleDialog.visible"
            :close-on-click-modal="false"
            :width="assignRoleDialog.width || '600px'">
            <sib-form v-bind="assignRoleDialog" @reset="assignRoleDialog.visible = false" @submit="handleSubmitAssignRole"></sib-form>
        </el-dialog>
    </div>
</template>

<script>
import { ref, computed, reactive, inject } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import verifications from '@/utils/verifications';
import tools from '@/utils/tools';

const { getToken, createTreeByList } = tools;

const passwordValidator = (rule, value, callback) => {
    if (!value || !verifications.passwordValid(value)) {
        callback(new Error('由字母,数字,特殊符号两种及以上组合'));
        return;
    }
    callback();
};

export default {
    name: 'SystemUser',
    setup() {
        const $axios = inject('$axios');
        const sibTableRef = ref(null);
        const isLoading = ref(false);
        const deptTreeData = ref([]);
        const treeRequestConfig = reactive({
            url: '/system/dept/list-all-simple',
            method: 'get',
            callback: ({ data }) => {
                const treeData = createTreeByList(data.data || []);
                deptTreeData.value = treeData;
                return treeData;
            },
        });
        // 查询模块表单配置
        const searchConfig = reactive({
            showExpand: false,
            rowFieldSize: 4,
            fields: [
                {
                    label: '用户名称',
                    code: 'username',
                    type: 'text',
                    maxlength: 100,
                },
                {
                    label: '手机号码',
                    code: 'mobile',
                    type: 'text',
                    maxlength: 100,
                },
                {
                    label: '状态',
                    code: 'status',
                    type: 'select',
                    optionProps: { label: 'label', value: 'value' },
                    requestConfig: {
                        url: '/system/dict/data/type/common_status',
                        method: 'get',
                    },
                    options: [],
                },
                {
                    label: '创建时间',
                    code: 'createTime',
                    type: 'daterange',
                    startCode: 'beginTime',
                    endCode: 'endTime',
                    // valueFormat: 'x',
                },
            ],
        });
        // 表格表头配置
        const tableColumn = ref([
            {
                label: '用户名称',
                code: 'username',
                minWidth: 100,
            },
            {
                label: '用户昵称',
                code: 'nickname',
                minWidth: 100,
            },
            {
                label: '部门',
                code: 'deptName',
                minWidth: 120,
            },
            {
                label: '手机号码',
                code: 'mobile',
                minWidth: 120,
            },
            {
                label: '状态',
                code: 'status',
                // type: 'switch',
                // activeValue: '0',
                // inactiveValue: '1',
                // beforeChange(value, { id, username }) {
                //     return new Promise((resolve, reject) => {
                //         const message = `确认要${String(value) === '0' ? '启用' : '停用'}${username}吗?`;
                //         ElMessageBox.confirm(message).then(() => {
                //             $axios.put('/system/user/update-status', { status: value, id }).then(() => {
                //                 resolve();
                //                 ElMessage.success('操作成功');
                //             }).catch(reject);
                //         }).catch(reject);
                //     });
                // },
            },
            {
                label: '创建时间',
                code: 'createTime',
                type: 'timeStamp',
                format: 'YYYY-MM-DD hh:mm',
                minWidth: 160,
            },
            {
                label: '操作',
                code: 'operate',
                type: 'slot',
                minWidth: 160,
                fixed: 'right',
            },
        ]);
        // 列表查询接口配置
        const requestConfig = reactive({
            url: '/system/user/page',
            method: 'get',
            params: {},
            // 自定义传参
            customSearchParams: obj => {
                const params = {};
                Object.keys(obj).forEach(key => {
                    if ([0, false].includes(obj[key]) || obj[key]) params[key] = obj[key];
                });
                if (params.beginTime) params.beginTime = +new Date(`${params.beginTime} 00:00:00`);
                if (params.endTime) params.endTime = +new Date(`${params.endTime} 23:59:59`);
                params.createTime = (params.createTime || []).map((t, i) => `${t} ${(['00:00:00', '23:59:59'][i])}`);
                return params;
            },
        });
        const importProps = reactive({
            type: 'upload',
            action: `${$axios.defaults.baseURL}/system/user/importData`,
            showTips: false,
            showFileList: false,
            icon: 'Upload',
            headers: { Authorization: `Bearer ${getToken()}` },
            onSuccess: res => {
                if (String(res.code) === '0') {
                    ElMessage.success('上传成功');
                    sibTableRef.value.getTableData();
                    return;
                }
                ElMessage.error(res.msg || '上传失败');
            },
            onError: () => {
                ElMessage.error('上传失败');
            },
        });

        // 弹窗类型 add/edit/reset
        const dialogType = ref('add');
        const dialogVisible = ref(false);
        const currentRow = reactive({ value: {} });
        // 新增、编辑等弹窗配置
        const dialogConfig = computed(() => ({
            title: ({ add: '新增用户信息', edit: '修改用户信息', reset: '重置密码' })[dialogType.value],
            width: '600px',
            rowFieldSize: dialogType.value === 'reset' ? 1 : 2,
            resetText: '取消',
            autoOperateBtnWidth: false,
            // 新增、编辑、查看的表单项配置
            fields: dialogType.value === 'reset' ? [
                {
                    label: '新密码',
                    code: 'password',
                    type: 'password',
                    maxlength: 20,
                    required: true,
                    rules: [
                        { min: 8, max: 20, message: '长度在 8 到 20 个字符', trigger: 'change' },
                        { validator: passwordValidator, trigger: 'change' },
                    ],
                },
            ] : [
                {
                    label: '用户昵称',
                    code: 'nickname',
                    type: 'text',
                    maxlength: 30,
                    required: true,
                },
                {
                    label: '归属部门',
                    code: 'deptId',
                    type: 'tree',
                    formatedValueCode: 'deptName',
                    optionProps: { label: 'name', value: 'id' },
                    data: deptTreeData.value,
                },
                {
                    label: '手机号码',
                    code: 'mobile',
                    type: 'text',
                    valueType: 'number',
                    maxlength: 11,
                },
                {
                    label: '邮箱',
                    code: 'email',
                    type: 'text',
                    maxlength: 50,
                },
                {
                    label: '用户名称',
                    code: 'username',
                    type: 'text',
                    maxlength: 20,
                    rules: [{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }],
                    required: true,
                    show: dialogType.value === 'add',
                },
                {
                    label: '用户密码',
                    code: 'password',
                    type: 'password',
                    maxlength: 20,
                    rules: [
                        { min: 8, max: 20, message: '长度在 8 到 20 个字符', trigger: 'blur' },
                        { validator: passwordValidator, trigger: 'blur' },
                    ],
                    required: true,
                    show: dialogType.value === 'add',
                },
                {
                    label: '用户性别',
                    code: 'sex',
                    type: 'select',
                    options: [],
                    requestConfig: {
                        url: '/system/dict/data/type/system_user_sex',
                        method: 'get',
                    },
                },
                {
                    label: '岗位',
                    code: 'postIds',
                    type: 'select',
                    multiple: true,
                    options: [],
                    optionProps: { label: 'name', value: 'id' },
                    requestConfig: {
                        url: '/system/post/list-all-simple',
                        method: 'get',
                    },
                },
                {
                    label: '备注',
                    code: 'remark',
                    type: 'textarea',
                    width: '100%',
                },
            ],
            form: currentRow.value || {},
        }));
        // 分配角色弹窗
        const assignRoleDialog = reactive({
            visible: false,
            width: '600px',
            resetText: '取消',
            fields: [
                {
                    label: '用户名称',
                    code: 'username',
                    type: 'text',
                    maxlength: 30,
                    required: true,
                    disabled: true,
                },
                {
                    label: '用户昵称',
                    code: 'nickname',
                    type: 'text',
                    maxlength: 30,
                    required: true,
                    disabled: true,
                },
                {
                    label: '角色',
                    code: 'roleIds',
                    type: 'select',
                    multiple: true,
                    options: [],
                    optionProps: { label: 'name', value: 'id' },
                    requestConfig: {
                        url: '/system/role/simple-list',
                        method: 'get',
                    },
                    required: true,
                },
            ],
            form: {},
        });

        return {
            isLoading,
            sibTableRef,
            treeRequestConfig,
            searchConfig,
            tableColumn,
            requestConfig,
            importProps,
            dialogType,
            dialogVisible,
            dialogConfig,
            assignRoleDialog,
            nodeClick(data) {
                requestConfig.params.deptId = data.id;
            },
            handleReset({ userId }) {
                dialogType.value = 'reset';
                currentRow.value = { userId };
                dialogVisible.value = true;
            },
            handleAdd() {
                dialogType.value = 'add';
                currentRow.value = {};
                dialogVisible.value = true;
            },
            handleEdit(row) {
                dialogType.value = 'edit';
                currentRow.value = { ...row, deptName: (row.dept || {}).name || '', password: '' };
                dialogVisible.value = true;
            },
            handleAssignRole(row) {
                $axios.get(`/system/permission/list-user-roles?userId=${row.id}`).then(res => {
                    const roleIds = res.data.data || [];
                    assignRoleDialog.form = { ...row, roleIds };
                    assignRoleDialog.visible = true;
                });
            },
            handleDelete(row) {
                ElMessageBox.confirm(`是否删除【${row.username}】`, '温馨提示').then(() => {
                    $axios.delete(`/system/user/delete?id=${row.id}`).then(() => {
                        ElMessage({ type: 'success', message: '删除成功' });
                        sibTableRef.value.getTableData();
                    });
                }).catch(() => {});
            },
            handleDownload() {
                isLoading.value = true;
                $axios.post('/system/user/get-import-template', {}, { responseType: 'blob' }).then(res => {
                    window.SIB.download(res, `用户导入模板_${new Date().getTime()}.xlsx`);
                    ElMessage({ type: 'success', message: '下载成功' });
                }).finally(() => {
                    isLoading.value = false;
                });
            },
            handleExport() {
                isLoading.value = true;
                $axios.post('/system/user/export', sibTableRef.value.searchParams || {}, { responseType: 'blob' }).then(res => {
                    window.SIB.download(res, `用户列表_${new Date().getTime()}.xlsx`);
                    ElMessage({ type: 'success', message: '导出成功' });
                }).finally(() => {
                    isLoading.value = false;
                });
            },
            handleSubmitAssignRole({ id: userId, roleIds }, cb) {
                const params = { userId, roleIds };
                $axios.post('/system/permission/assign-user-role', params).then(() => {
                    assignRoleDialog.visible = false;
                }).finally(cb);
            },
            handleSubmit(form, cb) {
                if (dialogType.value === 'reset') {
                    $axios.put('/system/user/update-password', form).then(() => {
                        dialogVisible.value = false;
                        sibTableRef.value.getTableData();
                        ElMessage({ type: 'success', message: `修改成功！新密码：${form.password}` });
                    }).finally(cb);
                    return;
                }
                const method = dialogType.value === 'edit' ? 'put' : 'post';
                $axios[method]('/system/user/create', form).then(() => {
                    dialogVisible.value = false;
                    sibTableRef.value.getTableData();
                }).finally(cb);
            },
        };
    },
};
</script>

<style lang="scss">
.system-user {
    display: flex;
    height: calc(100vh - 84px);

    .sib-table-operate {
        display: flex;
    }

    .sib-tree {
        width: 200px;
        height: 100%;
        padding-top: 10px;
        margin-right: 10px;

        /* stylelint-disable-next-line selector-class-pattern */
        .sib-tree__header {
            .el-input {
                padding-top: 0;
            }
        }
    }

    .sib-table {
        width: calc(100% - 210px);
        height: 100%;
    }
}
</style>
